package gotnames.web;

import gotnames.Utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import com.google.appengine.repackaged.org.json.JSONException;
import com.google.appengine.repackaged.org.json.JSONObject;
import com.medallia.tiny.Empty;

/**
 * Class which handles interaction with Facebook.
 */
public abstract class Facebook {
	private final String appId;
	private final String escapedAccessToken;

	/**
	 * @param appId the Facebook application id
	 * @param escapedAccessToken the escaped access token to include in Facebook requests
	 */
	public Facebook(String appId, String escapedAccessToken) {
		this.appId = appId;
		this.escapedAccessToken = escapedAccessToken;
	}
	
	/** @return the Facebook application id */
	public String getAppId() {
		return appId;
	}
	
	/** @return the unescaped access token; used for debugging purposes */
	public String getAccessToken() {
		return Utils.urlUnescape(escapedAccessToken);
	}
	
	/** @return the escaped access token; used for debugging purposes */
	public String getEscapedAccessToken() {
		return escapedAccessToken;
	}
	
	/**
	 * @return true if the Facebook authorization is present; if not the user
	 *         must be re-directed to a a page which does the authorization.
	 */
	public boolean isAuthorized() {
		return escapedAccessToken != null;
	}
	
	/** Execute a Facebook query to the given URL, e.g. 'me' */
	public JSONObject query(String url) throws JSONException {
		return exec(url, false);
	}

	/** Same as {@link #query(String)}, but pass a set of request parameters; even values as keys, odd are values */
	
	public JSONObject post(String url, String... args) throws JSONException {
		return exec(url, true, args);
	}
	
	private JSONObject exec(String url, boolean post, String... args) throws JSONException {
		if (!isAuthorized())
			throw new FbNotAuthorizedException();
		
		try {
			StringBuilder fullUrl = Empty.sb();
			fullUrl.append("https://graph.facebook.com/" + url + "?access_token=" + escapedAccessToken);
			for (int i = 0; i < args.length; i += 2)
				fullUrl.append("&" + args[i] + "=" + Utils.urlEscape(args[i + 1]));
			
			URL reqUrl = new URL(fullUrl.toString());
			System.out.println("url: " + reqUrl);
			HttpURLConnection connection = (HttpURLConnection) reqUrl.openConnection();
			if (post)
				connection.setRequestMethod("POST");
			
			BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
			
			StringBuilder data = Empty.sb();
			String line;
			while ((line = reader.readLine()) != null) {
				data.append(line);
				data.append("\n");
			}
			reader.close();
			
			JSONObject json = new JSONObject(data.toString());
			
			if (json.has("error")) {
				logout();
				throw new FbNotAuthorizedException(url + ": " + json.get("error"));
			}
			
			return json;
		} catch (MalformedURLException e) {
			throw new FbException(url, e);
		} catch (IOException e) {
			throw new FbException(url, e);
		}
	}
	
	protected abstract void logout();

	/** Exception thrown if the current authentication information is not valid */
	public static class FbNotAuthorizedException extends RuntimeException {
		public FbNotAuthorizedException() { }
		public FbNotAuthorizedException(String message) {
			super(message);
		}
	}
	
	/** Exception thrown if the response from Facebook is not well formed */
	public static class FbException extends RuntimeException {
		public FbException(String message) {
			super(message);
		}
		public FbException(String message, Throwable cause) {
			super(message, cause);
		}
	}

}
